package com.example.mylogin.config;

import com.example.mylogin.enums.OrderEvents;
import com.example.mylogin.enums.OrderStatus;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;

import java.util.EnumSet;

/**
 * <p>
 * 功能描述：the configuration of order state machine
 * </p>
 *
 * @author cui haida
 * @date 2025/06/07/20:50
 */
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderEvents> {

    /**
     * config the state of order
     *
     * @param states the state of order -> include the status and events
     * @throws Exception
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvents> states) throws Exception {
        states
                .withStates()
                .initial(OrderStatus.WAIT_PAYMENT) // define the initial state
                .states(EnumSet.allOf(OrderStatus.class)); // define the status
    }


    /**
     * config the transition of order
     *
     * @param transitions the transition of order -> include the source status and target status
     * @throws Exception if it has error in the transition, throw the exception
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvents> transitions) throws Exception {
        transitions
                // wait_payment -> pay -> wait_deliver
                .withExternal().source(OrderStatus.WAIT_PAYMENT)
                .target(OrderStatus.WAIT_DELIVER)
                .event(OrderEvents.PAYED)
                .and()
                // wait_deliver -> deliver -> wait_receive
                .withExternal().source(OrderStatus.WAIT_DELIVER)
                .target(OrderStatus.WAIT_RECEIVE)
                .event(OrderEvents.DELIVERY)
                .and()
                // wait_receive -> receive -> finish
                .withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderEvents.RECEIVED);
    }
}
